package cz.spock.core.dao;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.helper.DAOBase;

import cz.spock.cms.entity.Node;
import cz.spock.cms.entity.Project;
import cz.spock.core.entity.Account;
import cz.spock.core.entity.Hit;
import cz.spock.core.entity.Person;
import cz.spock.core.entity.Visit;
import cz.spock.core.entity.registration.Registration;
import cz.spock.core.entity.security.AccountSecurity;
import cz.spock.core.entity.security.SpockGrantedAuthority;

/**
 * see DAOBase code for more info
 * 
 * CoreDao is expected to be only DAO class in project for now
 * 
 * provides basic operations with entities, but app logic can also use objectify methods directly via ofy()
 * - get
 * - find - same as get but returns null if entity not present
 * - put
 * - delete
 * 
 * ! find methods should be used instead of get !
 * 
 * status: under development
 * 
 * @author miso
 *
 */
// TODO DAOBase off, implement all methods here
@Component
public class CoreDao extends DAOBase {
    
    @Autowired
    private ObjectifyFactory factory;
    private Objectify lazyOfy;
    
    //private ObjectifyOpts opts;
    
    // TODO registration??
    //entity registration
    static {
        ObjectifyService.register(Account.class);
        ObjectifyService.register(AccountSecurity.class);
        ObjectifyService.register(SpockGrantedAuthority.class);
    }

    //generic CRUD methods
    public <T> T get(Class<T> t, Long id) {
        if(t == null || id == null) return null;
        return this.ofy().get(t, id);
    }
    
    public <T> T get(Key<T> key) {
        if(key == null) return null;
        return this.ofy().get(key);
    }
    
    public <T> T find(Class<T> t, Long id) {
        if(t == null || id == null) return null;
        return this.ofy().find(t, id);
    }
    
    public <T> T find(Key<T> key) {
        if(key == null) return null;
        return this.ofy().find(key);
    }
    
    // persisting and updating entity in datastore
    public <T> Key<T> put(T entity) {
        if(entity == null) return null;
        return this.ofy().put(entity);
    }
    
    public <T> void delete(Class<T> t, Long id) {
        if(t == null || id == null) return;
        this.ofy().delete(t, id);
    }
    
    public <T> void delete(Key<T> key) {
        if(key == null) return;
        this.ofy().delete(key);
    }
    
    public <T> void delete(T object) {
        if(object == null) return;
        this.ofy().delete(object);
    }
    
    public <T> void deleteAll(Class<T> c) {
        if(c == null) return;
        List<T> list = this.ofy().query(c).list();
        this.ofy().delete(list);
    }
    
    /**
     * method used for development and testing purposes
     * DELETES ALL OBJECTS FROM DATASTORE!
     */
    public void deleteAll() {        
        deleteAll(Account.class);
        deleteAll(Hit.class);
        deleteAll(Person.class);
        deleteAll(Visit.class);
        
        deleteAll(Node.class);
        deleteAll(Project.class);
        
        deleteAll(Registration.class);
        
        deleteAll(AccountSecurity.class);
        deleteAll(SpockGrantedAuthority.class);
    }
    
    @Override
    public Objectify ofy() {
        if (this.lazyOfy == null)
            this.lazyOfy = this.factory.begin();
        return this.lazyOfy;
    }
    
}
